package core

import (
	"errors"
	"fmt"
	"gitee.com/hongzhaomin/gspring/annotation"
	"gitee.com/hongzhaomin/gspring/iface"
	"gitee.com/hongzhaomin/gspring/lock"
	"gitee.com/hongzhaomin/gspring/tools"
)

var _ iface.SingletonBeanRegistry = (*DefaultSingletonBeanRegistry)(nil)

type DefaultSingletonBeanRegistry struct {
	singletonPoolReentrantLock    *lock.ReentrantMutex // 可重入锁
	singletonObjects              map[string]any       // 成品对象单例池 map[beanName]object
	earlySingletonObjects         map[string]any       // 半成品对象单例池 map[beanName]object
	singletonsCurrentlyInCreation map[string]struct{}  // 正在创建中的对象名称Set集合
	destructibleSingletonObjects  map[string]struct{}  // 可销毁的对象名称Set集合
}

func NewDefaultSingletonBeanRegistry() *DefaultSingletonBeanRegistry {
	return &DefaultSingletonBeanRegistry{
		singletonPoolReentrantLock:    new(lock.ReentrantMutex),
		singletonObjects:              make(map[string]any, 256),
		earlySingletonObjects:         make(map[string]any, 16),
		singletonsCurrentlyInCreation: make(map[string]struct{}, 16),
		destructibleSingletonObjects:  make(map[string]struct{}, 16),
	}
}

func (my *DefaultSingletonBeanRegistry) GetSingleton(beanName string) any {
	bean, ok := my.singletonObjects[beanName]
	if !ok && my.IsSingletonCurrentlyInCreation(beanName) {
		bean, ok = my.earlySingletonObjects[beanName]
		if !ok {
			my.singletonPoolReentrantLock.Lock()
			defer my.singletonPoolReentrantLock.Unlock()
			bean, ok = my.singletonObjects[beanName]
			if !ok {
				bean, ok = my.earlySingletonObjects[beanName]
			}
		}
	}
	return bean
}

func (my *DefaultSingletonBeanRegistry) GetSingletonOrCreate(beanName string, getCompleteObject func() (error, any)) any {
	my.singletonPoolReentrantLock.Lock()
	defer my.singletonPoolReentrantLock.Unlock()
	singleton, ok := my.singletonObjects[beanName]
	if !ok {
		my.beforeSingletonCreation(beanName)
		err, newSingleton := getCompleteObject()
		my.afterSingletonCreation(beanName)
		if err != nil {
			singleton = my.GetSingleton(beanName)
			if singleton != nil {
				return singleton
			}
			panic(err)
		}

		if _, ok = my.singletonObjects[beanName]; !ok {
			my.addSingleton(beanName, newSingleton)
		}

		singleton = newSingleton
	}
	return singleton
}

func (my *DefaultSingletonBeanRegistry) RegisterSingleton(beanName string, singletonBean any) {
	tools.Assert().NotBlank(beanName, "bean name must not be blank")
	tools.Assert().NotNil(singletonBean, "singleton bean must not be nil")

	my.singletonPoolReentrantLock.Lock()
	defer my.singletonPoolReentrantLock.Unlock()
	_, ok := my.singletonObjects[beanName]
	tools.Assert().IsFalse(ok, fmt.Sprintf("could not register object [%s]: there is already exist", beanName))

	my.addSingleton(beanName, singletonBean)
}

func (my *DefaultSingletonBeanRegistry) addSingleton(beanName string, singletonBean any) {
	my.singletonObjects[beanName] = singletonBean
	delete(my.earlySingletonObjects, beanName)
	if _, ok := singletonBean.(annotation.Destroy); ok {
		my.destructibleSingletonObjects[beanName] = struct{}{}
	}
}

func (my *DefaultSingletonBeanRegistry) AddEarlySingleton(beanName string, earlySingleton any) any {
	my.singletonPoolReentrantLock.Lock()
	defer my.singletonPoolReentrantLock.Unlock()
	if _, ok := my.singletonObjects[beanName]; ok {
		panic(errors.New(fmt.Sprintf("singleton已经创建完成: %s", beanName)))
	}
	if oldEarlySingleton, ok := my.earlySingletonObjects[beanName]; ok {
		return oldEarlySingleton
	}
	my.earlySingletonObjects[beanName] = earlySingleton
	return earlySingleton
}

// IsSingletonCurrentlyInCreation 判断 beanName 的bean是否正在创建中
// @return true: 表示正在创建; false: 表示并非正在创建
func (my *DefaultSingletonBeanRegistry) IsSingletonCurrentlyInCreation(beanName string) bool {
	_, ok := my.singletonsCurrentlyInCreation[beanName]
	return ok
}

func (my *DefaultSingletonBeanRegistry) ContainsSingleton(beanName string) bool {
	_, ok := my.singletonObjects[beanName]
	return ok
}

func (my *DefaultSingletonBeanRegistry) beforeSingletonCreation(beanName string) {
	my.singletonPoolReentrantLock.Lock()
	defer my.singletonPoolReentrantLock.Unlock()
	tools.Assert().IsFalse(my.IsSingletonCurrentlyInCreation(beanName), fmt.Sprintf("bean [%s] 产生了无法解决的循环依赖问题", beanName))
	my.singletonsCurrentlyInCreation[beanName] = struct{}{}
}

func (my *DefaultSingletonBeanRegistry) afterSingletonCreation(beanName string) {
	my.singletonPoolReentrantLock.Lock()
	defer my.singletonPoolReentrantLock.Unlock()
	tools.Assert().IsTrue(my.IsSingletonCurrentlyInCreation(beanName), fmt.Sprintf("bean [%s] 当前未正在创建过程中", beanName))
	delete(my.singletonsCurrentlyInCreation, beanName)
}

func (my *DefaultSingletonBeanRegistry) DestroySingletons() {
	my.singletonPoolReentrantLock.Lock()
	defer my.singletonPoolReentrantLock.Unlock()
	for beanName := range my.destructibleSingletonObjects {
		singleton := my.GetSingleton(beanName)
		if singleton != nil {
			singleton.(annotation.Destroy).Destroyed()
		}
	}
	my.singletonObjects = make(map[string]any)
	my.earlySingletonObjects = make(map[string]any)
	my.singletonsCurrentlyInCreation = make(map[string]struct{})
	my.destructibleSingletonObjects = make(map[string]struct{})
}
